package cn.tedu.charging.order.config;

import cn.tedu.charging.order.mqtt.MqttConsumer;
import cn.tedu.charging.order.mqtt.MqttContext;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Random;

/**
 * EMQX消息中间件的 连接配置
 */
@Configuration
public class MqttConfiguration {
    /**
     * 用户名 这些配置类的信息 应该放到 配置文件 或者
     * nacos 中 (nacos 提供了服务注册和配置管理)
     */
    private String userName = "admin";

    /**
     * 密码
     */
    private String password = "public";

    /**
     * 连接地址 tcp协议 端口 1883
     */
    private String host = "tcp://localhost:1883";

    /**
     * 客户端id  启动多个订单服务 通过 getRandom() 会生成不同的 客户端id
     */
    private String clientId = "order_service_client_" + getRandom();


    private Integer getRandom(){
        Random random = new Random();
        return random.nextInt(100);
    }

    // 调用 MqttContext 注入，作为一个构造函数
    @Autowired
    private MqttContext mqttContext;

    @Bean
    public MqttClient mqttClient() throws Exception {

        /**
         * 想象一下你是一个公司员工，需要和另一个部门沟通：
         * mqttClient 就像公司的前台接待员
         * 你的代码（如 MqttConsumer）就像部门员工
         * 设备服务就像另一个部门
         */

        //通过连接地址和客户端id和emqx进行连接
        //客户端id 目的是要告诉我们的服务器 谁在连接它
        // 前台接待员（mqttClient）
        MqttClient mqttClient = new MqttClient(host, clientId);
        //连接相关的配置
        MqttConnectOptions conOpts = new MqttConnectOptions();
        //配置用户名
        conOpts.setUserName(userName);
        //配置密码
        conOpts.setPassword(password.toCharArray());
        //自动重连
        conOpts.setAutomaticReconnect(true);
        //版本号设置
        conOpts.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
        //清理会话session
        conOpts.setCleanSession(true);

        // 通过java里的关键字 new 创建一个MqttConsumer
        // 类型的对象 名字是 mqttConsumer 回调类
        /**
         * 创建回调处理器：使用 new 关键字创建一个 MqttConsumer 类的实例
         * 传递客户端引用：将 mqttClient 对象作为参数传递给 MqttConsumer 的构造器
         * 目的：让 MqttConsumer 能够访问和使用 mqttClient 对象来执行各种MQTT操作
         */
        MqttConsumer mqttConsumer = new MqttConsumer(mqttClient,mqttContext);
        // 把mqttConsumer回调类，设置给mqttClient
        // 同时要在 mqttConsumer 里面使用 容器里的 mqttClient，通过 mqttClient 来订阅 topic
        /**
         * 注册回调：将 MqttConsumer 实例设置为 mqttClient 的回调处理器
         * 事件处理：当 mqttClient 收到消息、连接状态改变等事件时，会自动调用 MqttConsumer 中定义的方法
         * 职责分离：将MQTT通信逻辑（mqttClient）和业务逻辑（MqttConsumer）分离
         */
        // 部门员工（MqttConsumer）告诉前台："我需要接收充电结果"
        mqttClient.setCallback(mqttConsumer);   // 绑定：通过 setCallback() 方法将 MqttConsumer 绑定到 mqttClient

        //基于上面配置的 conOpts 进行连接 和emqx
        // 前台接待员（mqttClient）连接到公司总机（MQTT Broker）
        mqttClient.connect(conOpts);
        return mqttClient;
    }

}
